package org.davekeen.controls {
	/**
	 * ...
	 * @author Dave Keen
	 */
	
	import flash.events.MouseEvent;
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	import mx.containers.HBox;
	import mx.containers.VBox;
	import mx.controls.Button;
	import mx.core.UIComponent;
	import mx.events.FlexEvent;
	import org.flexunit.flexui.TestRunnerBase;
	import org.flexunit.listeners.UIListener;
	import org.flexunit.runner.FlexUnitCore;
	import mx.controls.Tree;
	
	public class TestRunnerTreeBase extends UIComponent {
		
		private var _suites:Array;
		
		private var core:FlexUnitCore;
		private var uiListener:UIListener;
		private var testRunnerBase:TestRunnerBase;
		
		private var hBox:HBox;
		private var tree:Tree;
		private var runAllButton:Button;
		private var runButton:Button;
		
		public function set runClass(c:Class):void {
			if (c) runClasses(c);
		}
		
		public function set suites(suites:Array):void {
			_suites = suites;
			
			populateFlexUnitTree();
		}
		
		private function populateFlexUnitTree():void {
			var data:Array = [ ];
			
			for each (var suiteClass:Class in _suites) {
				var suite:Object = { };
				
				suite.label = ClassUtil.getClassAsString(suiteClass);
				suite.data = suiteClass;
				
				var children:Array = [ ];
				for each (var variable:XML in describeType(suiteClass)..variable) {
					var test:Object = { };
					
					test.label = variable.@name;
					test.data = getDefinitionByName(variable.@type) as Class;
					
					children.push(test);
				}
				
				if (children.length > 0) suite.children = children;
				
				data.push(suite);
			}
			
			tree.dataProvider = data;
		}
		
		override protected function createChildren():void {
			super.createChildren();
			
			hBox = new HBox();
			
			var vBox:VBox = new VBox();
			vBox.percentWidth = 20;
			vBox.percentHeight = 100;
			
			runAllButton = new Button();
			runAllButton.label = "Run all";
			runAllButton.percentWidth = 100;
			runAllButton.addEventListener(MouseEvent.CLICK, onRunAllButtonClick);
			
			tree = new Tree();
			tree.percentWidth = tree.percentHeight = 100;
			
			runButton = new Button();
			runButton.label = "Run";
			runButton.percentWidth = 100;
			runButton.addEventListener(MouseEvent.CLICK, onRunButtonClick);
			
			vBox.addChild(runAllButton);
			vBox.addChild(tree);
			vBox.addChild(runButton);
			
			hBox.addChild(vBox);
			
			addChild(hBox);
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			hBox.width = unscaledWidth;
			hBox.height = unscaledHeight;
		}
		
		private function onRunButtonClick(e:MouseEvent):void {
			runClasses(tree.selectedItem.data);
		}
		
		private function onRunAllButtonClick(e:MouseEvent):void {
			runClasses(_suites);
		}
			
		private function runClasses(classes:*):void {
			if (tree.selectedItems) {
				if (core && uiListener && testRunnerBase) {
					core.removeListener(uiListener);
					hBox.removeChild(testRunnerBase);
				}
				
				core = new FlexUnitCore();
				
				testRunnerBase = new TestRunnerBase();
				testRunnerBase.percentWidth = 100;
				testRunnerBase.percentHeight = 100;
				hBox.addChild(testRunnerBase);
				
				testRunnerBase.addEventListener(FlexEvent.CREATION_COMPLETE, function():void {
					uiListener = new UIListener(testRunnerBase);
					core.addListener(uiListener);
					
					if (classes is Array) {
						core.run(classes);
					} else {
						core.runClasses(classes);
					}
				} );
			}
		}
		
	}

}

import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;

class ClassUtil {
	
	/**
	 * Return the class of an object as a Class (useful for 'is' comparisons)
	 * 
	 * @param	obj
	 * @return
	 */
	public static function getClass(obj:Object):Class {
		return (obj) ? Class(getDefinitionByName(getQualifiedClassName(obj))) : null;
	}
	
	/**
	 * Returns the class of an object as a String
	 * 
	 * @param	obj
	 * @return
	 */
	public static function getClassAsString(obj:Object):String {
		return formatClassAsString(getClass(obj));
	}
	
	/**
	 * Returns the full package and class - for example calling the method on an instance of this class would return org.davekeen.flextrine.util.ClassUtil
	 * Useful for logging targets which don't accept the :: notation of getQualifiedClassName.
	 * 
	 * @param	obj
	 * @return
	 */
	public static function getQualifiedClassNameAsString(obj:Object):String {
		return getQualifiedClassName(obj).replace("::", ".");
	}
	
	public static function formatClassAsString(c:Object):String {
		if (!(c is Class))
			throw new Error("This method must take a Class as an argument");
			
		return c.toString().match(/\[class (\w*)\]/)[1];
	}
}